/**************************************************************************************************
**                                                                                               **
**  文件名称:  dal_uart_drv.c                                                                    **
**  版权所有:  CopyRight @ Xiamen Yaxon NetWork CO.LTD. 2017                                     **
**  文件描述:  串口抽象化驱动                                                                    **
**  ===========================================================================================  **
**  创建信息:  | 2017-7-8 | LEON | 创建本模块                                                    **
**  ===========================================================================================  **
**  修改信息:  单击此处添加....                                                                  **
**************************************************************************************************/
#include "dal_include.h"
#include "dal_uart_reg.h"
#include "dal_uart_drv.h"

/*************************************************************************************************/
/*                           模块宏定义                                                          */
/*************************************************************************************************/
#define _COMOPEN             0x01                                              /* 串口已经打开 */
#define _SENDING             0x08                                              /* 正在发送数据 */

#define DMA_TX_LEN           64                                                /* 发送缓冲区长度 */
#define DMA_RX_LEN           32                                                /* 接收缓冲区长度 */

/*************************************************************************************************/
/*                           模块结构体定义                                                      */
/*************************************************************************************************/
typedef struct {
    INT8U       status;                                                        /* 串口状态 */
    
    INT8U       dma_tx[DMA_TX_LEN];                                            /* DMA发送缓冲区 */
    INT8U      *ptr_tbuf;                                                      /* 指向动态发送内存 */
    INT32U      len_tbuf;                                                      /* 动态内存长度 */
    ROUNDBUF_T  round_tx;                                                      /* 发送环形缓冲区 */
    
    INT8U       index;                                                         /* 当前使用哪个缓冲区 */
    INT8U       dma_rx0[DMA_RX_LEN];                                           /* DMA接收缓冲区1 */
    INT8U       dma_rx1[DMA_RX_LEN];                                           /* DMA接收缓冲区2 */
    INT8U      *ptr_rbuf;                                                      /* 指向动态接收内存 */
    INT32U      len_rbuf;                                                      /* 动态内存长度 */
    ROUNDBUF_T  round_rx;                                                      /* 发送环形缓冲区 */
} UART_T;

/*************************************************************************************************/
/*                           静态变量定义                                                        */
/*************************************************************************************************/
static UART_T   s_uartctrl[UART_COM_MAX];

/**************************************************************************************************
**  函数名称:  StartTxDMA
**  功能描述:  启动串口DMA发送功能
**  输入参数:  uart_id: 串口通道编号；memaddr: DMA内存地址；memlen:  发送数据长度
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
static void StartTxDMA(INT8U com, INT8U *memaddr, INT16U memlen)
{
    const UART_TBL_T *pinfo;
    DMA_Channel_TypeDef  *dma_channel;
    
    pinfo = DAL_UART_GetRegTblInfo(com);
    dma_channel = (DMA_Channel_TypeDef *)pinfo->dma_base_tx;
    
    DMA_Cmd(dma_channel, DISABLE);
    DMA_ITConfig(dma_channel, DMA_IT_TC, DISABLE);
    
    dma_channel->CMAR  = (INT32U)memaddr;
    dma_channel->CNDTR = memlen;
    
    DMA_ITConfig(dma_channel, DMA_IT_TC, ENABLE);
    DMA_Cmd(dma_channel, ENABLE);
}

/**************************************************************************************************
**  函数名称:  TXDMAHdl
**  功能描述:  DMA发送中断处理
**  输入参数:  com: 通道编号，见UART_COM_E
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
static void TXDMAHdl(INT8U com)
{
    INT16U i, bufsize;
    const UART_TBL_T *pinfo;
    
    if (com >= UART_COM_MAX) {
        return;
    }
            
    pinfo = DAL_UART_GetRegTblInfo(com);
    if (((s_uartctrl[com].status & _COMOPEN) == 0) || ((s_uartctrl[com].status & _SENDING) == 0)) {
        DMA_Cmd((DMA_Channel_TypeDef *)pinfo->dma_base_tx, DISABLE);
        DMA_ITConfig((DMA_Channel_TypeDef *)pinfo->dma_base_tx, DMA_IT_TC, DISABLE);
        return;
    }
    
    bufsize = RBUF_GetUsedByte(&s_uartctrl[com].round_tx);
    if (bufsize == 0) {
        s_uartctrl[com].status &= (~_SENDING);
        DMA_ITConfig((DMA_Channel_TypeDef *)pinfo->dma_base_tx, DMA_IT_TC, DISABLE);
        DMA_Cmd((DMA_Channel_TypeDef *)pinfo->dma_base_tx, DISABLE);
        return;
    }
    
    if (bufsize > DMA_TX_LEN) {
        bufsize = DMA_TX_LEN;
    }
    
    for (i = 0; i < bufsize; i++) {
        s_uartctrl[com].dma_tx[i] = RBUF_ReadByte_INT(&s_uartctrl[com].round_tx);
    }
    
    StartTxDMA(com, s_uartctrl[com].dma_tx, bufsize);
}

/**************************************************************************************************
**  函数名称:  RXIRQHdl
**  功能描述:  UART接收中断处理
**  输入参数:  com: 通道编号，见UART_COM_E；uart_base: uart寄存器基址；data: 字节数据
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
static void RXIRQHdl(INT8U com, INT32U uart_base, INT16U data)
{
    if (com >= UART_COM_MAX) {
        return;
    }
    
    if ((s_uartctrl[com].status & _COMOPEN) != 0) {
        RBUF_WriteByte_INT(&s_uartctrl[com].round_rx, data);
    } else {
        USART_ITConfig((USART_TypeDef *)uart_base, USART_IT_RXNE, DISABLE);
    }
}

/*******************************************************************
** 函数名称: TXDMAHdl_Channel2
** 函数描述: DMA1_CHANNEL2中断处理(UART1 TX for DMA CH2/ UART1 RX for DMA CH3)
** 参数:     无
** 返回:     无
********************************************************************/
static void TXDMAHdl_Channel2(void)
{
    if (RESET != DMA_GetITStatus(DMA1_IT_TC2)) {
        DMA_ClearITPendingBit(DMA1_IT_TC2);
        TXDMAHdl(UART_COM_0);
    }
}

/*******************************************************************
** 函数名称: TXDMAHdl_Channel4
** 函数描述: DMA1_CHANNEL4中断处理(UART2 TX for DMA CH4/ UART2 RX for DMA CH5)
** 参数:     无
** 返回:     无
********************************************************************/
static void TXDMAHdl_Channel4(void)
{
    if (RESET != DMA_GetITStatus(DMA1_IT_TC4)) {
        DMA_ClearITPendingBit(DMA1_IT_TC4);
        TXDMAHdl(UART_COM_1);
    }

    if (RESET != DMA_GetITStatus(DMA1_IT_TC7)) {
        DMA_ClearITPendingBit(DMA1_IT_TC7);
        TXDMAHdl(UART_COM_3);
    }
}

/*******************************************************************
** 函数名称: RXIRQHdl_UART1
** 函数描述: uart1中断服务程序
** 参数:     无
** 返回:     无
********************************************************************/
static void RXIRQHdl_UART1(void)
{
    INT16U data;
    
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        data = USART1->RDR & 0x01FF;
        RXIRQHdl(UART_COM_0, (INT32U)USART1_BASE, data);
    }
    
    if (USART_GetFlagStatus(USART1, USART_FLAG_ORE) != RESET) {                /* 必须处理一下溢出中断 */
        USART_ClearFlag(USART1, USART_FLAG_ORE);
    }
}

/*******************************************************************
** 函数名称: RXIRQHdl_UART2
** 函数描述: uart2中断服务程序
** 参数:     无
** 返回:     无
********************************************************************/
static void RXIRQHdl_UART2(void)
{
    INT16U data;

    if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) {
        data = USART2->RDR & 0x01FF;
        RXIRQHdl(UART_COM_1, (INT32U)USART2_BASE, data);
    }
    
    if (USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET) {                /* 必须处理一下溢出中断 */
        USART_ClearFlag(USART2, USART_FLAG_ORE);
    }
}

/*******************************************************************
** 函数名称: RXIRQHdl_UART3
** 函数描述: uart3中断服务程序
** 参数:     无
** 返回:     无
********************************************************************/
static void RXIRQHdl_UART3(void)
{
    INT16U data;
    
    if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) {
        data = USART3->RDR & 0x01FF;
        RXIRQHdl(UART_COM_3, (INT32U)USART3_BASE, data);
    }
    
    if (USART_GetFlagStatus(USART3, USART_FLAG_ORE) != RESET) {                /* 必须处理一下溢出中断 */
        USART_ClearFlag(USART3, USART_FLAG_ORE);
    }
}

/**************************************************************************************************
**  函数名称:  UART_PINConfig
**  功能描述:  管脚配置
**  输入参数:  pinfo: 配置表；onoff: 打开/关闭串口，TRUE-打开串口，FALSE-关闭串口
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
static void UART_PINConfig(const UART_TBL_T *pinfo, INT8U onoff)
{
    GPIO_InitTypeDef gpio_initstruct;
    
    if (pinfo == 0) {
        return;
    }
    
    if (pinfo->uart_remap != 0) {
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
    }
    
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);                        /* 开启GPIO系统时钟 */
    
    gpio_initstruct.GPIO_Pin   = (INT16U)(1 << pinfo->uart_pin_tx);
    gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;
    gpio_initstruct.GPIO_OType = GPIO_OType_PP;
    gpio_initstruct.GPIO_PuPd  = GPIO_PuPd_UP;
    
    if (onoff) {
        gpio_initstruct.GPIO_Mode  = GPIO_Mode_AF;
        GPIO_Init((GPIO_TypeDef *)pinfo->gpio_base, &gpio_initstruct);
        if (pinfo->gpio_base == GPIOB_BASE) {
            GPIO_PinAFConfig((GPIO_TypeDef *)pinfo->gpio_base, pinfo->uart_pin_tx, GPIO_AF_0);
        } else {
            GPIO_PinAFConfig((GPIO_TypeDef *)pinfo->gpio_base, pinfo->uart_pin_tx, GPIO_AF_1);
        }
    } else {
        gpio_initstruct.GPIO_Mode  = GPIO_Mode_OUT;
        GPIO_Init((GPIO_TypeDef *)pinfo->gpio_base, &gpio_initstruct);
        GPIO_ResetBits((GPIO_TypeDef *)pinfo->gpio_base, (INT16U)(1 << pinfo->uart_pin_tx));
    }
    
    gpio_initstruct.GPIO_Pin   = (INT16U)(1 << pinfo->uart_pin_rx);
    gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;
    gpio_initstruct.GPIO_OType = GPIO_OType_PP;
    gpio_initstruct.GPIO_PuPd  = GPIO_PuPd_UP;
    
    if (onoff) {
        gpio_initstruct.GPIO_Mode  = GPIO_Mode_AF;
        GPIO_Init((GPIO_TypeDef *)pinfo->gpio_base, &gpio_initstruct);
        if (pinfo->gpio_base == GPIOB_BASE) {
            GPIO_PinAFConfig((GPIO_TypeDef *)pinfo->gpio_base, pinfo->uart_pin_rx, GPIO_AF_0);
        } else {
            GPIO_PinAFConfig((GPIO_TypeDef *)pinfo->gpio_base, pinfo->uart_pin_rx, GPIO_AF_1);
        }
    } else {
        gpio_initstruct.GPIO_Mode  = GPIO_Mode_OUT;
        GPIO_Init((GPIO_TypeDef *)pinfo->gpio_base, &gpio_initstruct);
        GPIO_ResetBits((GPIO_TypeDef *)pinfo->gpio_base, (INT16U)(1 << pinfo->uart_pin_rx));
    }
}

/**************************************************************************************************
**  函数名称:  UART_DMAConfig
**  功能描述:  配置UART发送为DMA方式
**  输入参数:  pinfo: 配置参数
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
static void UART_DMAConfig(const UART_TBL_T *pinfo)
{
    INT32S irq_id;
    BOOLEAN is_dma1;
    IRQ_SERVICE_FUNC handle;
    DMA_InitTypeDef init;
    
    if (pinfo == 0) {
        return;
    }
    
    if (pinfo->dma_base_tx != 0) {                                             /* 配置发送通道 */
        
        switch (pinfo->dma_base_tx)
        {
            case DMA1_Channel2_BASE:
                irq_id  = DMA1_Channel2_3_IRQn;
                handle  = (IRQ_SERVICE_FUNC)TXDMAHdl_Channel2;
                is_dma1 = TRUE;
                break;
                
            case DMA1_Channel4_BASE:
            case DMA1_Channel7_BASE:
                irq_id  = DMA1_Channel4_5_6_7_IRQn;
                handle  = (IRQ_SERVICE_FUNC)TXDMAHdl_Channel4;
                is_dma1 = TRUE;
                break;
                
            default:
                return;
        }
        
        if (is_dma1) {
            RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
        }
    
        DMA_DeInit((DMA_Channel_TypeDef *)pinfo->dma_base_tx);                 /* 恢复DMA通道 */
    
        DMA_StructInit(&init);
        
        init.DMA_PeripheralBaseAddr  = (INT32U)&(((USART_TypeDef *)pinfo->uart_base)->TDR);/* 外设基准地址 */
        init.DMA_MemoryBaseAddr      = 0;                                      /* 内存基准地址 */
        init.DMA_DIR                 = DMA_DIR_PeripheralDST;                  /* 通道方向 */
        init.DMA_BufferSize          = 0;                                      /* 内存缓存大小 */
        init.DMA_PeripheralInc       = DMA_PeripheralInc_Disable;              /* 外设地址不自增 */
        init.DMA_MemoryInc           = DMA_MemoryInc_Enable;                   /* 内存地址自增 */
        init.DMA_PeripheralDataSize  = DMA_PeripheralDataSize_Byte;            /* 字节模式 */
        init.DMA_MemoryDataSize      = DMA_MemoryDataSize_Byte;                /* 字节模式 */
        init.DMA_Mode                = DMA_Mode_Normal;                        /* 正常模式 */
        init.DMA_Priority            = DMA_Priority_Low;                 
        init.DMA_M2M                 = DMA_M2M_Disable;
    
        DMA_Init((DMA_Channel_TypeDef *)pinfo->dma_base_tx, &init);
        IRQ_ConfigEnable(irq_id, false);
        IRQ_InstallHandler(irq_id, handle);
        IRQ_ConfigPriority(irq_id, IRQ_PRIOTITY_TXDMA);
        IRQ_ConfigEnable(irq_id, true);
    }
    
    if (pinfo->dma_base_rx != 0) {                                             /* 配置接收通道 */
        
        switch (pinfo->dma_base_rx)
        {
            case DMA1_Channel3_BASE:
                irq_id  = DMA1_Channel2_3_IRQn;
                handle  = (IRQ_SERVICE_FUNC)TXDMAHdl_Channel2;
                is_dma1 = TRUE;
                break;
                
            case DMA1_Channel5_BASE:
            case DMA1_Channel6_BASE:
                irq_id  = DMA1_Channel4_5_6_7_IRQn;
                handle  = (IRQ_SERVICE_FUNC)TXDMAHdl_Channel4;
                is_dma1 = TRUE;
                break;
                
            default:
                return;
        }
    
        if (is_dma1) {
            RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
        }
    
        DMA_DeInit((DMA_Channel_TypeDef *)pinfo->dma_base_rx);                 /* 恢复DMA通道 */
    
        DMA_StructInit(&init);
        
        init.DMA_PeripheralBaseAddr  = (INT32U)&(((USART_TypeDef *)pinfo->uart_base)->RDR);        /* 外设基准地址 */
        init.DMA_MemoryBaseAddr      = (INT32U)s_uartctrl[pinfo->com].dma_rx0;                     /* 内存基准地址 */
        init.DMA_DIR                 = DMA_DIR_PeripheralSRC;                  /* 通道方向 */
        init.DMA_BufferSize          = DMA_RX_LEN;                             /* 内存缓存大小 */
        init.DMA_PeripheralInc       = DMA_PeripheralInc_Disable;              /* 外设地址不自增 */
        init.DMA_MemoryInc           = DMA_MemoryInc_Enable;                   /* 内存地址自增 */
        init.DMA_PeripheralDataSize  = DMA_PeripheralDataSize_Byte;            /* 字节模式 */
        init.DMA_MemoryDataSize      = DMA_MemoryDataSize_Byte;                /* 字节模式 */
        init.DMA_Mode                = DMA_Mode_Normal;                        /* 正常模式 */
        init.DMA_Priority            = DMA_Priority_Low;                 
        init.DMA_M2M                 = DMA_M2M_Disable;
        
        s_uartctrl[pinfo->com].index = 0;
    
        DMA_Init((DMA_Channel_TypeDef *)pinfo->dma_base_rx, &init);
    
        IRQ_ConfigEnable(irq_id, false);
        IRQ_InstallHandler(irq_id, handle);
        IRQ_ConfigPriority(irq_id, IRQ_PRIOTITY_RXDMA);
        IRQ_ConfigEnable(irq_id, true);
    }
}

/**************************************************************************************************
**  函数名称:  UART_IRQConfig
**  功能描述:  配置串口中断功能
**  输入参数:  pinfo : 配置参数；inter : 中断配置
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
static void UART_IRQConfig(const UART_TBL_T *pinfo)
{
    INT32S irq_id;
    IRQ_SERVICE_FUNC handle;
    
    if (pinfo == 0) {
        return;
    }
    
    switch (pinfo->uart_base)
    {
        case USART1_BASE:
            irq_id = USART1_IRQn;
            handle = (IRQ_SERVICE_FUNC)RXIRQHdl_UART1;
            break;
            
        case USART2_BASE:
            irq_id = USART2_IRQn;
            handle = (IRQ_SERVICE_FUNC)RXIRQHdl_UART2;
            break;
            
        case USART3_BASE:
            irq_id = USART3_4_IRQn;
            handle = (IRQ_SERVICE_FUNC)RXIRQHdl_UART3;
            break;
            
        default:
            return;
    }
    
    IRQ_ConfigEnable(irq_id, false);
    IRQ_InstallHandler(irq_id, handle);
    IRQ_ConfigPriority(irq_id, IRQ_PRIOTITY_UART);
    IRQ_ConfigEnable(irq_id, true);
}

/**************************************************************************************************
**  函数名称:  STM32_UART_Init
**  功能描述:  串口通信参数配置，并设置是否支持DMA
**  输入参数:  cfg:串口配置参数 
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
static void STM32_UART_Init(UART_CFG_T *cfg)
{
    INT8U com;
    INT16U stopbit, databit, parity, mode;
    INT32U baud;
    USART_InitTypeDef usart_initstruct;
    const UART_TBL_T *pinfo;
      
    com = cfg->com;
    pinfo = DAL_UART_GetRegTblInfo(com);
            
    if (pinfo->uart_base == USART1_BASE) {
        RCC_APB2PeriphClockCmd(pinfo->uart_rcc, ENABLE);
    } else {
        RCC_APB1PeriphClockCmd(pinfo->uart_rcc, ENABLE);
    }
    
    baud = cfg->baud;
    
    switch (cfg->databit)
    {
        case UART_DATABIT_8:
            databit = USART_WordLength_8b;
            break;
        case UART_DATABIT_9:
            databit = USART_WordLength_9b;
            break;
        default:
            databit = USART_WordLength_8b;
            break;
    }
         
    switch (cfg->stopbit)
    {
        case UART_STOPBIT_1:
            stopbit = USART_StopBits_1;
            break;
        case UART_STOPBIT_1_5:
            stopbit = USART_StopBits_1_5;
            break;
        case UART_STOPBIT_2:
            stopbit = USART_StopBits_2;
            break;
        case UART_STOPBIT_0_5:
            stopbit = USART_StopBits_1;
            break;
        default:
            stopbit = USART_StopBits_1;
            break;
    }
    
    switch (cfg->parity)
    {
        case UART_PARITY_NONE:
            parity = USART_Parity_No;
            break;
        case UART_PARITY_EVEN:
            parity = USART_Parity_Even;
            break;
        case UART_PARITY_ODD:
            parity = USART_Parity_Odd;
            break;
        default:
            parity = USART_Parity_No;
            break;
    }
    
    mode = USART_Mode_Rx | USART_Mode_Tx;
    
    USART_Cmd((USART_TypeDef *)pinfo->uart_base, DISABLE);
    USART_DeInit((USART_TypeDef *)pinfo->uart_base);
    
    usart_initstruct.USART_BaudRate            = baud;
    usart_initstruct.USART_WordLength          = databit;
    usart_initstruct.USART_StopBits            = stopbit;
    usart_initstruct.USART_Parity              = parity;
    usart_initstruct.USART_Mode                = mode;
    usart_initstruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

    USART_Init((USART_TypeDef *)pinfo->uart_base, &usart_initstruct);
    
    if (pinfo->dma_base_tx != 0 && pinfo->dma_base_rx != 0) {
        USART_DMACmd((USART_TypeDef *)pinfo->uart_base, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);
        UART_IRQConfig(pinfo);
        USART_ITConfig((USART_TypeDef *)pinfo->uart_base, USART_IT_IDLE, ENABLE);
    } else if (pinfo->dma_base_tx != 0) {
        USART_DMACmd((USART_TypeDef *)pinfo->uart_base, USART_DMAReq_Tx, ENABLE);
        UART_IRQConfig(pinfo);
        USART_ITConfig((USART_TypeDef *)pinfo->uart_base, USART_IT_RXNE, ENABLE);
    } else if (pinfo->dma_base_rx != 0) {
        USART_DMACmd((USART_TypeDef *)pinfo->uart_base, USART_DMAReq_Rx, ENABLE);
        UART_IRQConfig(pinfo);
        USART_ITConfig((USART_TypeDef *)pinfo->uart_base, USART_IT_TXE, ENABLE);
        USART_ITConfig((USART_TypeDef *)pinfo->uart_base, USART_IT_IDLE, ENABLE);
    } else {
        UART_IRQConfig(pinfo);
        USART_ITConfig((USART_TypeDef *)pinfo->uart_base, USART_IT_RXNE, ENABLE);
        USART_ITConfig((USART_TypeDef *)pinfo->uart_base, USART_IT_TXE, ENABLE);
    }
    
    USART_Cmd((USART_TypeDef *)pinfo->uart_base, ENABLE);
}

/**************************************************************************************************
**  函数名称:  DAL_UART_InitDrv
**  功能描述:  初始化串口驱动
**  输入参数:  无
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
void DAL_UART_InitDrv(void)
{
    memset(&s_uartctrl, 0, sizeof(s_uartctrl));
}

/**************************************************************************************************
**  函数名称:  DAL_UART_OpenUart
**  功能描述:  打开串口并初始化
**  输入参数:  cfg:串口配置参数 
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
BOOLEAN DAL_UART_OpenUart(UART_CFG_T *cfg)
{
    INT8U com;
    const UART_TBL_T *pinfo;
    
    SYS_ASSERT((cfg != 0), RETURN_FALSE);
    SYS_ASSERT((cfg->com < UART_COM_MAX), RETURN_FALSE);
    SYS_ASSERT((cfg->tx_len != 0), RETURN_FALSE);
    SYS_ASSERT((cfg->rx_len != 0), RETURN_FALSE);
    
    com = cfg->com;
    pinfo = DAL_UART_GetRegTblInfo(com);
    
    if (pinfo->enable == 0) {
        return false;
    }
    
    if ((s_uartctrl[com].status & _COMOPEN) != 0) {                                   /* 串口已打开 */
        s_uartctrl[com].status &= ~(_COMOPEN | _SENDING);
        USART_Cmd((USART_TypeDef *)pinfo->uart_base, DISABLE);
        USART_DeInit((USART_TypeDef *)pinfo->uart_base);
        
        if (pinfo->dma_base_tx != 0) {
            DMA_DeInit((DMA_Channel_TypeDef *)pinfo->dma_base_tx);
        }
        
        if (pinfo->dma_base_rx != 0) {
            DMA_DeInit((DMA_Channel_TypeDef *)pinfo->dma_base_rx);
        }
    }
    
    if (s_uartctrl[com].ptr_rbuf == 0 || s_uartctrl[com].len_rbuf != cfg->rx_len) {
        if (s_uartctrl[com].ptr_rbuf != 0) {
            SysMem_Free(s_uartctrl[com].ptr_rbuf);
        }
        s_uartctrl[com].ptr_rbuf = SysMem_Alloc(cfg->rx_len);
        if (s_uartctrl[com].ptr_rbuf == 0) {
            return false;
        }
        
        s_uartctrl[com].len_rbuf = cfg->rx_len;
        RBUF_InitBuf(&s_uartctrl[com].round_rx, s_uartctrl[com].ptr_rbuf, s_uartctrl[com].len_rbuf);
    }
    
    if (s_uartctrl[com].ptr_tbuf == 0 || s_uartctrl[com].len_tbuf != cfg->tx_len) {
        if (s_uartctrl[com].ptr_tbuf != 0) {
            SysMem_Free(s_uartctrl[com].ptr_tbuf);
        }
        s_uartctrl[com].ptr_tbuf = SysMem_Alloc(cfg->tx_len);
        if (s_uartctrl[com].ptr_tbuf == 0) {
            return false;
        }
        
        s_uartctrl[com].len_tbuf = cfg->tx_len;
        RBUF_InitBuf(&s_uartctrl[com].round_tx, s_uartctrl[com].ptr_tbuf, s_uartctrl[com].len_tbuf);
    }
    
    UART_PINConfig(pinfo, TRUE);
    UART_DMAConfig(pinfo);
    STM32_UART_Init(cfg);
    
    s_uartctrl[com].status = _COMOPEN;
    return true;
}

/**************************************************************************************************
**  函数名称:  DAL_UART_CloseUart
**  功能描述:  关闭串口
**  输入参数:  com: 通道编号，见UART_COM_E
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
BOOLEAN DAL_UART_CloseUart(INT8U com)
{
    const UART_TBL_T *pinfo;
    
    if (com >= UART_COM_MAX) {
        return false;
    }
    
    pinfo = DAL_UART_GetRegTblInfo(com);
    
    if (pinfo->enable == 0) {
        return false;
    }
        
    if ((s_uartctrl[com].status & _COMOPEN) != 0) {                                   /* 串口已打开 */
        s_uartctrl[com].status &= ~(_COMOPEN | _SENDING);
        UART_PINConfig(pinfo, FALSE);
        USART_Cmd((USART_TypeDef *)pinfo->uart_base, DISABLE);
        USART_DeInit((USART_TypeDef *)pinfo->uart_base);
        
        if (pinfo->dma_base_tx != 0) {
            DMA_DeInit((DMA_Channel_TypeDef *)pinfo->dma_base_tx);
        }
        
        if (pinfo->dma_base_rx != 0) {
            DMA_DeInit((DMA_Channel_TypeDef *)pinfo->dma_base_rx);
        }
    }
    
    s_uartctrl[com].status &= ~(_COMOPEN | _SENDING);
    
    if (s_uartctrl[com].ptr_rbuf != 0) {
        SysMem_Free(s_uartctrl[com].ptr_rbuf);
        s_uartctrl[com].ptr_rbuf = 0;
        s_uartctrl[com].len_rbuf = 0;
    }
    
    if (s_uartctrl[com].ptr_tbuf != 0) {
        SysMem_Free(s_uartctrl[com].ptr_tbuf);
        s_uartctrl[com].ptr_tbuf = 0;
        s_uartctrl[com].len_tbuf = 0;
    }
    
    return true;
}

/**************************************************************************************************
**  函数名称:  DAL_UART_ReadChar
**  功能描述:  获取一个字节数据
**  输入参数:  com: 通道编号，见UART_COM_E
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
INT32S DAL_UART_ReadChar(INT8U com)
{
    if (com >= UART_COM_MAX) {
        return -1;
    }
    
    if ((s_uartctrl[com].status & _COMOPEN) == 0) {
        return -1;
    }
    
    return RBUF_ReadByte(&s_uartctrl[com].round_rx);
}

/**************************************************************************************************
**  函数名称:  DAL_UART_WriteChar
**  功能描述:  发送一个字节
**  输入参数:  com: 通道编号，见UART_COM_E；data: 字节数据
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
BOOLEAN DAL_UART_WriteChar(INT8U com, INT8U data)
{
    INT8U result;
    INT16U i, bufsize;

    if (com >= UART_COM_MAX) {
        return FALSE;
    }
    
    if ((s_uartctrl[com].status & _COMOPEN) == 0) {
        return FALSE;
    }
    
    result = RBUF_WriteByte(&s_uartctrl[com].round_tx, data);
    
    ENTER_CRITICAL();
    if ((s_uartctrl[com].status & _SENDING) == 0) {
        EXIT_CRITICAL();
        
        bufsize = RBUF_GetUsedByte(&s_uartctrl[com].round_tx);
        if (bufsize > 0) {
            if (bufsize > DMA_TX_LEN) {
                bufsize = DMA_TX_LEN;
            }
    
            for (i = 0; i < bufsize; i++) {
                s_uartctrl[com].dma_tx[i] = RBUF_ReadByte(&s_uartctrl[com].round_tx);
            }
            
            s_uartctrl[com].status |= _SENDING;
            StartTxDMA(com, s_uartctrl[com].dma_tx, bufsize);
        }
    } else {
        EXIT_CRITICAL();
    }
    
    return result;
}

/**************************************************************************************************
**  函数名称:  DAL_UART_WriteCharWait
**  功能描述:  发送一个字节，并等待发送完毕
**  输入参数:  com: 通道编号，见UART_COM_E；data: 字节数据
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
BOOLEAN DAL_UART_WriteCharWait(INT8U com, INT8U data)
{
    const UART_TBL_T *pinfo;
    
    if (com >= UART_COM_MAX) {
        return false;
    }
    
    pinfo = DAL_UART_GetRegTblInfo(com);
    if (pinfo->enable == 0) {
        return false;
    }
    
    ((USART_TypeDef *)pinfo->uart_base)->TDR = (data & 0x01FF);
    while ((((USART_TypeDef *)pinfo->uart_base)->ISR & 0x80) == 0) {};
    
    return true;
}

/**************************************************************************************************
**  函数名称:  DAL_UART_WriteBlock
**  功能描述:  发送一串数据
**  输入参数:  com: 通道编号，见UART_COM_E；sptr: 数据指针；slen: 数据长度
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
BOOLEAN DAL_UART_WriteBlock(INT8U com, INT8U *sptr, INT16U slen)
{
    INT8U result;
    INT16U i, bufsize;
      
    if ((sptr == 0) || (slen == 0)) {
        return FALSE;
    }
    
    if (com >= UART_COM_MAX) {
        return FALSE;
    }
    
    if ((s_uartctrl[com].status & _COMOPEN) == 0) {
        return FALSE;
    }
    
    result = RBUF_WriteBlock(&s_uartctrl[com].round_tx, sptr, slen);
        
    ENTER_CRITICAL();
    if ((s_uartctrl[com].status & _SENDING) == 0) {
        EXIT_CRITICAL();
        
        bufsize = RBUF_GetUsedByte(&s_uartctrl[com].round_tx);
        if (bufsize > 0) {
            if (bufsize > DMA_TX_LEN) {
                bufsize = DMA_TX_LEN;
            }
    
            for (i = 0; i < bufsize; i++) {
                s_uartctrl[com].dma_tx[i] = RBUF_ReadByte(&s_uartctrl[com].round_tx);
            }

            s_uartctrl[com].status |= _SENDING;
            StartTxDMA(com, s_uartctrl[com].dma_tx, bufsize);
        }
    } else {
        EXIT_CRITICAL();
    }
    
    return result;
}

/**************************************************************************************************
**  函数名称:  DAL_UART_GetRecvBytes
**  功能描述:  获取已接收字节数
**  输入参数:  com: 通道编号，见UART_COM_E
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
INT32U DAL_UART_GetRecvBytes(INT8U com)
{
    if (com >= UART_COM_MAX) {
        return 0;
    }
    
    if ((s_uartctrl[com].status & _COMOPEN) == 0) {
        return 0;
    }
    
    return RBUF_GetUsedByte(&s_uartctrl[com].round_rx);
}

/**************************************************************************************************
**  函数名称:  DAL_UART_LeftOfSendbuf
**  功能描述:  获取发送缓存剩余空间
**  输入参数:  com: 通道编号，见UART_COM_E
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
INT32U DAL_UART_LeftOfSendbuf(INT8U com)
{
    if (com >= UART_COM_MAX) {
        return 0;
    }
    
    if ((s_uartctrl[com].status & _COMOPEN) == 0) {
        return 0;
    }
    
    return RBUF_GetLeftByte(&s_uartctrl[com].round_tx);
}



